/**********************************************
*  Classes:   Camera
*  Desc:      Defines a camera. Derives 
*			  from TransformNode. 
*  Author:    Vaios Kalpias-Ilias (C) 2008-2009
***********************************************/

#ifndef CAMERA_H
#define CAMERA_H

#include "TransformNode.h"
#include "Frustrum3.h"

class CdnRenderer;

class Camera : public TransformNode
{
public:

	Camera();
	virtual ~Camera();

	
	virtual const NodeType GetType() const
	{
		return NODE_CAMERA;
	}

	void SetTarget (TransformNodePtr target)
	{
		m_spTarget = target;
		m_bUpdateFrustrum = true;
	}

	void SetTarget (const mth::Vector3& target)
	{
		if (m_spTarget)
		{
			m_spTarget = TransformNodePtr();
		}
		m_vTargetPosSet = target;
		m_bUpdateFrustrum = true;
	}

	void SetUpdateFrustrum (bool v)
	{
		m_bUpdateFrustrum = v;
	}


	mth::Vector3 GetUp () const
	{
		return GetRotation().GetColumn(1);
	}

	mth::Vector3 GetRight () const
	{
		return GetRotation().GetColumn(0);
	}

	const mth::Vector3& GetGlobalUp () const
	{
		return m_vGlobalUp;
	}

	const mth::Vector3& GetGlobalRight () const
	{
		return m_vGlobalRight;
	}

	const mth::Vector3& GetTargetPos() const
	{
		return m_vTargetPos;
	}

	const Frustrum3& GetFrustrum() const
	{
		return m_Frustrum;
	}

	void SetAlwaysLookForward (bool value)
	{
		m_bLookForward = value;
	}


	void SetFrustrum (const Frustrum3& f)
	{
		m_Frustrum = f;
	}
	

	float GetNearDist() const
	{
		return m_fNearDist;
	}
	
	float GetFarDist() const
	{
		return m_fFarDist;
	}
	
	float GetFOV() const
	{
		return m_fFov;
	}

	float GetAspectRatio() const
	{
		return m_fRatio;
	}

	void SetNearDist(float d)
	{
		m_fNearDist = d;
		UpdateProjectionData();
	}

	void SetFarDist(float d)
	{
		m_fFarDist = d;
		UpdateProjectionData();
	}

	void SetFOV(float fov)
	{
		m_fFov = fov;
		UpdateProjectionData();
	}

	bool UpdateProjectionFlag() const
	{
		return m_bUpdateProjection;
	}

	void SetUpdateProjectionFlag (bool v)
	{
		m_bUpdateProjection = v;
	}

	
	// updates the camera's frustrum
	void UpdateFrustrum();

	
protected:

	TransformNodePtr m_spTarget;
	// final target position
	mth::Vector3 m_vTargetPos;
	// target position set by the user
	mth::Vector3 m_vTargetPosSet;
	// up vector
	mth::Vector3  m_vGlobalUp;
	// right vector
	mth::Vector3  m_vGlobalRight;
	// forward vector
	mth::Vector3 m_vForward;	
	// quaternion that is used to adjust rotation when
	// we are looking towards a target
	mth::Quaternion m_qLookAtQuat;
	// always look forward
	bool m_bLookForward;
	// the camera's view frustrum
	Frustrum3 m_Frustrum;
	// projection matrix data
	float m_fNearDist;
	float m_fFarDist;
	float m_fFov;
	float m_fHnear;
	float m_fRatio;
	float m_fWnear;
	float m_fHfar;
	float m_fWfar;
	bool m_bUpdateProjection;
	bool m_bUpdateFrustrum;
	// ptr to renderer
	CdnRenderer* m_pRenderer;
	
	virtual void PreUpdate();
	void UpdateProjectionData();
	
	
};

SmartPointer(Camera);

#endif